﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace FNN.Genetic.Mutations
{
    public class SynapseMutation : Mutation
    {
        /// <summary>
        ///     Конструктор на основе типа мутации
        /// </summary>
        /// <param name="mutationType">Тип мутации</param>
        public SynapseMutation(MutationTypes mutationType)
        {
            MutationTargetValue = MutationTargets.Synapse;
            MutationTypeValue = mutationType;
        }

        /// <summary>
        ///     Конструктор на основе ДНК и типа мутации
        /// </summary>
        /// <param name="targetDna">Целевая ДНК</param>
        /// <param name="mutationType">Тип мутации</param>
        public SynapseMutation(DnaHelix targetDna, MutationTypes mutationType)
        {
            MutationTargetValue = MutationTargets.Synapse;
            MutationTypeValue = mutationType;
            TargetDnaValue = targetDna;
        }

        /// <summary>
        ///  Запустить мутацию
        /// </summary>
        public override void Execute()
        {
            var targetChain = TargetDnaValue.SynapsesChain;
            var layerStructures = TargetDnaValue.GetNetworkStructure().LayerStructures;

            List<string> targetList = targetChain.Split('|').ToList();
            int randomSynapsePosition;
            int firstLayerIndex;
            int secondLayerIndex;
            int firstNeuronId;
            int secondNeuronId;

            switch (MutationTypeValue)
            {
                case MutationTypes.Additive:
                    randomSynapsePosition = MutationRandomizer.Next(0, targetList.Count + 1);
                    firstLayerIndex = MutationRandomizer.Next(0, layerStructures.Length + 1);
                    secondLayerIndex = MutationRandomizer.Next(0, layerStructures.Length + 1);
                    firstNeuronId = (firstLayerIndex + 1) * 1000 + MutationRandomizer.Next(0,
                        layerStructures[firstLayerIndex].FunctionsList.Length + 1) + 1;
                    secondNeuronId = (secondLayerIndex + 1) * 1000 + MutationRandomizer.Next(0,
                        layerStructures[secondLayerIndex].FunctionsList.Length + 1) + 1;
                    targetList.Insert(randomSynapsePosition, firstNeuronId + ";" + secondNeuronId + ";" + (0.05));
                    break;
                case MutationTypes.Destructive:
                    randomSynapsePosition = MutationRandomizer.Next(0, targetList.Count);
                    targetList.Remove(targetList.ElementAt(randomSynapsePosition));
                    break;
                case MutationTypes.Transformative:
                    randomSynapsePosition = MutationRandomizer.Next(0, targetList.Count);
                    firstLayerIndex = MutationRandomizer.Next(0, layerStructures.Length + 1);
                    secondLayerIndex = MutationRandomizer.Next(0, layerStructures.Length + 1);
                    firstNeuronId = (firstLayerIndex + 1) * 1000 + MutationRandomizer.Next(0,
                        layerStructures[firstLayerIndex].FunctionsList.Length + 1) + 1;
                    secondNeuronId = (secondLayerIndex + 1) * 1000 + MutationRandomizer.Next(0,
                        layerStructures[secondLayerIndex].FunctionsList.Length + 1) + 1;
                    var targetSynapseArray = targetList.ElementAt(randomSynapsePosition).Split(';');
                    targetSynapseArray[0] = firstNeuronId.ToString();
                    targetSynapseArray[1] = secondNeuronId.ToString();
                    targetList[randomSynapsePosition] = String.Join(";", targetSynapseArray); 
                    break;
            }
            targetChain = string.Join("|", targetList);
            TargetDnaValue.SynapsesChain = targetChain;
        }

        /// <summary>
        ///     Запустить мутацию с параметрами
        /// </summary>
        /// <param name="targetDna">Целевая ДНК</param>
        /// <param name="mutationType">Тип мутации</param>
        public override void Execute(DnaHelix targetDna, MutationTypes mutationType)
        {
            TargetDnaValue = targetDna;
            MutationTargetValue = MutationTargets.Synapse;
            MutationTypeValue = mutationType;
            Execute();
        }
    }
}
